package com.hframe.plugin.wechat;

import com.hframe.Json.JsonFiletr;
import com.hframe.data.DRef;
import com.hframe.http.client.*;
import com.hframe.type.*;
import com.hframe.typefilter.NameToEnum;
import com.sun.istack.internal.NotNull;
import org.apache.log4j.Logger;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信接口
 * Created by heqian on 17-9-19.
 */
public class WechatInterfac {
    private static Logger log = Logger.getLogger(WechatInterfac.class);
    private static Map<String, DAccessToken> accessTokenMap = new HashMap<>();
    protected DConfig config = null;

    public WechatInterfac(@NotNull DConfig config) {
        this.config = config;
    }

    /**
     * 获得微信的Access_Token，在一定时间内需要重新刷新获得
     *
     * @return
     */
    public String getAccess_Token() {
        DAccessToken token;
        synchronized (accessTokenMap) {
            token = accessTokenMap.get(config.appID);
        }

        if (null != token) {
            if (System.currentTimeMillis() - token.createTime.get() < token.expires_in.get() * 995)
                return token.access_token.get();
        }

        final DAccessToken[] ret = new DAccessToken[1];
        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DAccessToken>(DAccessToken.class) {
            @Override
            public void onData(DAccessToken data) {
                ret[0] = data;
            }
        });

        KeyParam param = new KeyParam();
        param.addParam("grant_type", "client_credential");
        param.addParam("appid", config.appID.get());
        param.addParam("secret", config.appSecret.get());
        clients.get("https://api.weixin.qq.com/cgi-bin/token", param);

        synchronized (accessTokenMap) {
            accessTokenMap.put(config.appID.get(), ret[0]);
        }
        return ret[0].access_token.get();
    }

    /**
     * 获得媒体
     *
     * @param mediaId   媒体ID
     * @param directory 媒体目录
     * @return
     */
    public String getMedia(@NotNull String mediaId, @NotNull String directory) {
        final String[] ret = new String[1];
        try {
            File file = new File(directory);
            if (!file.exists() && !file.isDirectory())
                file.mkdirs();
            if (!file.exists() && !file.isDirectory())
                throw new Exception("不是一个有效的目录     " + directory);


            HttpClients clients = new HttpClients();
            clients.setSuccess(new FileSuccess(directory) {
                @Override
                public void onFinish(String path) {
                    ret[0] = path;
                }
            });

            KeyParam param = new KeyParam();
            param.addParam("access_token", getAccess_Token());
            param.addParam("media_id", mediaId);
            clients.get("http://file.api.weixin.qq.com/cgi-bin/media/get", param);

        } catch (Exception e) {
            log.error(e, e);
        }
        return ret[0];
    }

    /**
     * 上传媒体
     *
     * @param filePath 媒体文件
     * @param meida    媒体类型
     * @return
     */
    public DataMeida updateMeida(@NotNull String filePath, @NotNull EnumMeida meida) {
        final DataMeida[] ret = new DataMeida[1];
        File file = new File(filePath);

        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DataMeida>(DataMeida.class) {
            @Override
            public void onData(DataMeida data) {
                ret[0] = data;
            }
        });
        String urls = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + getAccess_Token() + "&&type=" + meida.name();
        clients.post(urls, new FileParam(file));
        return ret[0];
    }

    /**
     * 获取用户列表，一次拉取调用最多拉取10000个关注者的OpenID
     *
     * @param nextOpenId 当公众号关注者数量超过10000时，可通过填写next_openid的值，从而多次拉取列表的方式来满足需求。
     * @return
     */
    public DataUserList userGetList(String nextOpenId) {
        final DataUserList[] ret = new DataUserList[1];
        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DataUserList>(DataUserList.class) {
            @Override
            public void onData(DataUserList data) {
                ret[0] = data;
            }
        });

        KeyParam param = new KeyParam();
        param.addParam("access_token", getAccess_Token());
        if (null != nextOpenId)
            param.addParam("next_openid", nextOpenId);
        clients.get("https://api.weixin.qq.com/cgi-bin/user/get", param);

        return ret[0];
    }


    /**
     * 创建用户标签
     *
     * @param tagName 标签名（30个字符以内）
     * @return
     */
    public DataTag tagCreate(@NotNull String tagName) {
        final DataTag[] ret = new DataTag[1];
        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DataTag>(DataTag.class) {
            @Override
            public void onData(DataTag data) {
                ret[0] = data;
            }
        });

        DataTag tag = new DataTag();
        tag.tag.set(new DataTagObject());
        tag.tag.get().name.set(tagName);
        try {
            tag.tag.filter(JsonFiletr.class).setKeys("name");
        } catch (Exception e) {
            log.error(e, e);
        }

        String urls = "https://api.weixin.qq.com/cgi-bin/tags/create?access_token=" + getAccess_Token();
        clients.post(urls, new DataParam(tag, "tag"));
        return ret[0];
    }

    /**
     * 获取公众号已创建的标签列表
     *
     * @return
     */
    public DataTags tagGetList() {
        final DataTags[] ret = new DataTags[1];
        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DataTags>(DataTags.class) {
            @Override
            public void onData(DataTags data) {
                ret[0] = data;
            }
        });

        KeyParam param = new KeyParam();
        param.addParam("access_token", getAccess_Token());
        clients.get("https://api.weixin.qq.com/cgi-bin/tags/get", param);
        return ret[0];
    }

    /**
     * 删除用户标签
     *
     * @param id
     * @return
     */
    public DResult tagRemove(@NotNull int id) {
        final DResult[] ret = new DResult[1];
        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DResult>(DResult.class) {
            @Override
            public void onData(DResult data) {
                ret[0] = data;
            }
        });

        DataTag tag = new DataTag();
        tag.tag.set(new DataTagObject());
        tag.tag.get().id.set(id);
        try {
            tag.tag.filter(JsonFiletr.class).setKeys("id");
        } catch (Exception e) {
            log.error(e, e);
        }

        String urls = "https://api.weixin.qq.com/cgi-bin/tags/delete?access_token=" + getAccess_Token();
        clients.post(urls, new DataParam(tag, "tag"));
        return ret[0];
    }

    /**
     * 获取用户基本信息（包括UnionID机制）
     *
     * @param openId   普通用户的标识，对当前公众号唯一
     * @param language 返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
     * @return 用户基本信息
     */
    public DUserInfo userGetInfo(@NotNull String openId, @NotNull EnumLanguage language) {
        final DUserInfo[] ret = new DUserInfo[1];
        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DUserInfo>(DUserInfo.class) {
            @Override
            public void onData(DUserInfo data) {
                ret[0] = data;
            }
        });

        KeyParam param = new KeyParam();
        param.addParam("access_token", getAccess_Token());
        param.addParam("openid", openId);
        param.addParam("lang", language.name());
        clients.get("https://api.weixin.qq.com/cgi-bin/user/info", param);
        return ret[0];
    }

    /**
     * 批量获取用户基本信息（包括UnionID机制）
     *
     * @param openId   普通用户的标识，对当前公众号唯一
     * @param language 返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
     * @return 用户基本信息
     */
    public DataUserInfos userGetInfos(@NotNull String openId, @NotNull EnumLanguage language, String... openids) {
        if (0 == openids.length)
            return null;

        final DataUserInfos[] ret = new DataUserInfos[1];
        HttpClients clients = new HttpClients();
        clients.setSuccess(new DataSuccess<DataUserInfos>(DataUserInfos.class) {
            @Override
            public void onData(DataUserInfos data) {
                ret[0] = data;
            }
        });
        try {
            DataUserInfos list = new DataUserInfos();
            for (String id : openids) {
                DUserInfo info = new DUserInfo();
                info.openid.set(id);
                info.language.set(language);
                info.language.filter(JsonFiletr.class).setName("lang");
                list.user_info_list.add(info);
            }

            JsonFiletr filter = list.user_info_list.filter(JsonFiletr.class);
            filter.setKeys("openid", "language");
            filter.setName("user_list");

            String urls = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=" + getAccess_Token();
            clients.post(urls, new DataParam(list));
        } catch (Exception e) {
            log.error(e, e);
        }
        return ret[0];
    }

    public static class DataUserInfos extends DResult {
        public TArray<DUserInfo> user_info_list = new TArray<>(DUserInfo.class);
    }

    public static class DataTag extends DResult {
        public TData<DataTagObject> tag = new TData<>(DataTagObject.class);
    }

    public static class DataTags extends DResult {
        public TArray<DataTagObject> tags = new TArray<>(DataTagObject.class);
    }

    public static class DataTagObject extends DRef<DataTagObject> {
        public TInt id = new TInt();
        public TInt count = new TInt();
        public TString name = new TString();
    }

    public static class DataUserList extends DResult {
        public TLong total = new TLong();
        public TInt count = new TInt();
        public TString next_openid = new TString();
        public TData<DataUserObject> data = new TData<>(DataUserObject.class);
    }

    public static class DataUserObject extends DRef<DataUserObject> {
        public TArray<TString> openid = new TArray<>(TString.class);
    }

    public static class DataMeida extends DResult {
        public TString media_id = new TString();
        public TLong created_at = new TLong();
        public TEnum<EnumMeida> type = new TEnum<>(EnumMeida.class);

        public DataMeida() {
            try {
                type.filter(JsonFiletr.class).setSetCall(new NameToEnum(EnumMeida.class));
            } catch (Exception e) {
                log.error(e, e);
            }
        }
    }
}
